﻿

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using MiniErp.Common.Cache;
using MiniErp.Common.DB.MySqlDB;
using MiniErp.Common.Https;
using MiniErp.Core.Auth;
using MiniErp.Core.Filters;
using MiniErp.Entity.JWTs;
using MiniErp.Repository.BaseRepository;
using MiniErp.Repository.MysqlRepository.IRepository;
using MiniErp.Repository.MysqlRepository.IRepository.AssetManagement;
using MiniErp.Repository.MysqlRepository.Repository;
using MiniErp.Repository.MysqlRepository.Repository.AssetManagement;
using MiniErp.Repository.UnitOfWorkCore;
using MiniErp.Service.JWTService.IService;
using MiniErp.Service.JWTService.Service;
using MiniErp.Service.BusinessService.IService;
using MiniErp.Service.BusinessService.IService.AssetManagement;
using MiniErp.Service.BusinessService.IService.IAssetManagement;
using MiniErp.Service.BusinessService.IService.Notice;
using MiniErp.Service.BusinessService.IService.Rights;
using MiniErp.Service.BusinessService.Service;
using MiniErp.Service.BusinessService.Service.AssetManagement;
using MiniErp.Service.BusinessService.Service.Notice;
using MiniErp.Service.BusinessService.Service.Rights;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using MiniErp.Common.AutoMapperConfig;

namespace MiniErp.Core
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            #region DB
            services.AddDbContext<MysqlContext>(options =>
               options.UseMySQL(Configuration.GetConnectionString("DefaultConnection")));
            //注册仓储
            services.AddTransient<IAssetInfoRepository, AssetInfoRepository>();
            services.AddTransient<IAssetModificationRecordRepository, AssetModificationRecordRepository>();
            //注册服务
            #region AssetManagement
            services.AddTransient<IAssetIndexService, AssetIndexService>();
            services.AddTransient<IAssetRecordService, AssetRecordService>();
            #endregion 
            #region Rights
            services.AddTransient<IRightsService, RightsService>();
            #endregion
            #region Notice
            services.AddTransient<INoticeService, NoticeService>();
            services.AddTransient<IUserInfoNoticesReplyService, UserInfoNoticesReplyService>();
            #endregion
            services.AddTransient<IUserService, UserService>();
            //注册工作单元
            services.AddTransient<IMysqlUnitOfWork, MysqlUnitOfWork>();
            #endregion
            #region JWT
            services.AddTransient<ITokenService, TokenService>();
            services.Configure<JWTTokenOPotions>(Configuration.GetSection("JWTTokenOPotions"));
            var tokenOPotions = new JWTTokenOPotions();
            Configuration.Bind("JWTTokenOPotions", tokenOPotions);


            services.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
                options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler);    //403
            })
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = tokenOPotions.Issuer,
                    ValidAudience = tokenOPotions.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOPotions.SecurityKey)),
                    ClockSkew = TimeSpan.Zero
                };
            })
            .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
            services.AddScoped<IPermissionHandler, PermissionHandler>();
            #endregion
            #region Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "MiniErp.Core", Version = "v1" });
                //添加安全定义
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "格式为：Bearer token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                //添加安全要求
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                    {
                        Reference=new OpenApiReference
                        {
                            Type=ReferenceType.SecurityScheme,
                            Id="Bearer"
                        }
                    },new string[]{ }
                    }
                });
                //Swagger显示方法体注释（右键项目=》属性=》建置=》隐藏警告改为1701;1702;1591，勾选XML文件档案）
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.XML";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });
            #endregion
            #region redis  
            // install - package Microsoft.Extensions.Caching.Redis
            //   管理员控制台进入Redis目录然后  redis - server.exe redis.windows.conf
            //services.AddDistributedRedisCache(options =>
            //{
            //    options.InstanceName = "";
            //    options.Configuration = "127.0.0.1:6379";
            //});

            var csredis = new CSRedis.CSRedisClient((Configuration.GetConnectionString("RedisConnection")));
            RedisHelper.Initialization(csredis);
            services.AddSingleton<ICache, RedisCache>();

            #endregion
            //注册AutoMapper
            services.AddAutoMapper(typeof(ProfileConfig));
            //注册Httpcontext
            services.AddHttpContextAccessor();
            //注册静态路由访问
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            //注册Https请求帮助类
            services.AddSingleton<IVisitHttps, VisitHttps>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MiniErp.Core v1"));
            }

            app.UseHttpsRedirection();
            //认证
            app.UseAuthentication();
            //路由
            app.UseRouting();
            //授权
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
